home *** CD-ROM | disk | FTP | other *** search
-
- DOC file for TrapIIv1.59 © 1990-1994 Nicolas Dade.
- Permission is hereby granted for non-commercial distribution and duplication.
- last changed: Dec 30th, 1994
-
- TrapII is of no use of you are not programming in a compiled language. It is
- of greatest use to an assembly language programmer.
-
- Some of the things TrapII does fall in the category of hacks, so no
- guarantee is stated or implied by the author concerning the suitability of
- this program for any purpose what so ever, and the author can take no
- responsibility as to any damages, disappointments, etc... that follow the
- (attempted) use of this program. However, on the bright side, this program
- has worked as described on the author's 68010 A1000 and a 68030 A2000
- under WB2.1, and under WB3.0 with a 68040.
-
- TrapII tries to help you (the programmer) by giving you much more
- information when your program (hereafter also referred to as the target)
- causes the 680x0 to enter exception handling code. That is, now when the
- target tries to read/write a word/long from/to an odd address, instead of
- getting a requestor, followed by a GURU which tells you it was you program
- that had the odd address, you get a (SMART refresh) window from TrapII...
-
-
-
- The contents of the window TrapII opens for each trap are best explained
- by looking at an example:
- To see this example in real life, open a CLI, cd to the directory TrapII
- is in, and type the following two lines:
- run <nil: >nil: TrapII
- run demo
- (you MUST run the demo, and not simply execute the demo!)
- (you can also do this from workbench--doubleclick on TrapII, and then on Demo)
-
- the source for demo is as follows:
- TRAP #$0 ; cause a TRAP #$0 trap
- TRAP #$F ; cause a TRAP #$F trap
- MOVEQ.L #9,d0
- MOVEQ.L #0,d1
- label ; this loop is used to demo [Trace] and [Next]
- ADDQ.L #1,d1
- DBF.W d0,label
- TRAP #1 ; cause a TRAP #$1 trap
- BSR.S subroutine ; used to demo [Next]
- MOVE.W D0,label+1 ; cause an address error trap
- CLR.L D0 ; actually, this instruction is never reached
- RTS
-
- subroutine
- MOVE.W #$FFFF,D2
- MOVE.W #$004F,D3
- sub_loop
- DBF.W D2,sub_loop
- DBF.W D3,sub_loop
- RTS
-
- You should see, in the workbench screen, a window looking like:
-
- ++
- line 1 |D nnnnnnnn A nnnnnnnn FUNC -,-,----|
- 2 |1 nnnnnnnn 1 nnnnnnnn ---- |
- 3 |2 nnnnnnnn 2 nnnnnnnn ADDR --------|
- 4 |3 nnnnnnnn 3 nnnnnnnn /--------,--|
- 5 |4 nnnnnnnn 4 nnnnnnnn INST ---- |
- 6 |5 nnnnnnnn 5 nnnnnnnn (SP) nnnnnnnn|
- 7 |6 nnnnnnnn 6 nnnnnnnn 4() nnnnnnnn|
- 8 |7 nnnnnnnn SP nnnnnnnn 8() nnnnnnnn|
- 9 | SR nnnnnnnnnnnnnnnn C() nnnnnnnn|
- 10 | T-S--III---XNZVC TRAP #$0 |
- 11 | PC nnnnnnnn/00000002,00 ++
- 12 |PROC demo |RemTask()|
- 13 | nnnnnnnn +++++
- 14 |hh:mm:ss?m |Restart| Next | Trace |
- +++++
-
- (n,h,m and s represent values that may be different each time demo is run)
- (n represents a hex number, hh,mm,ss represent decimal)
- the information is grouped in fields, as shown below:
-
- ++
- line 1 | | | |
- 2 | Data Regs | Addr Regs| Address Data|
- 3 | | | |
- 4 | | | AD |
- 5 | DR | AR |_____________|
- 6 | | | |
- 7 | | | Top of Stack|
- 8 |___________|__________| SK |
- 9 | |_____________|
- 10 | SR & PC |___Trap__TP__|
- 11 |________________________| |
- 12 | Task TK _____________| Gadgets |
- 13 |__________| GG |
- 14 | Time TM | (or status) |
- ++
-
- ** DR **
- The data registers as they were then the trap occurred. The contents are
- given as hexadecimal unsigned longs.
- (When I write trap, I mean when the 68000 entered exception processing
- code. When I write TRAP, I mean the TRAP #n instruction.)
-
- ** AR **
- The address registers as they were then the trap occurred. The contents are
- given as unsigned longs. SP (A7), is the user stack pointer (USP), regardless
- of what the 68000's mode was when the trap occured.
-
- ** SR **
- The status register (SR) the 680x0 pushed on the stack when the trap occur-
- red, in binary. Below (line 10) is the meaning of the bits of the SR for a
- 68000.
-
- ** PC **
- The PC the 680x0 pushed on the stack when the trap occurred, given two
- ways.
- The first is the absolute value of the PC. This points to the instruction
- following the instruction that caused the trap, except in the case of bus,
- address and illegal instruction errors, in which case it may point to
- somewhere in the instruction that caused the trap. The PC points to the
- next instruction in memory, not the next it would have executed. Thus if
- the offending instruction was a JMP (to an odd address), for example, the
- PC points to just beyond the JMP in memory, not the address to jump to.
- This representation of the PC is useful if you are using a disassembler
- or debugger to look in memory. If you are using a disassembler,
- get is started and look at the address PC. You should see the code for
- demo, with the PC pointing to the second TRAP instruction (the TRAP #$f).
- The second representation of the PC (after the "/") is the offset from the
- start of the hunk the PC points in, followed by the hex number of that
- hunk (0 = first hunk). So 00000002,00 indicates that the PC points to an
- address 2 bytes beyond the start of the first hunk. A look at the source
- for demo (above) will show the PC points to the instruction following the
- first TRAP #0. This value is usefull for looking at the listing the assembler
- created, and for some disassemblers and debuggers which look at the segment
- lists of loaded commands.
- (The hunk number must be less than 255, or no hunk number will be displayed)
-
- ** SK **
- These are the top four long words on the user stack. These are correct
- even if the USP is odd. Line 6 shows the topmost data. These are only useful
- in conjunction with a disassembler (if the trap occurred in a subroutine,
- you can see from where that routine was called).
-
- ** TP **
- This is a text description of the trap that occurred. Currently it says a
- TRAP #$0 instruction was reached. It can also say:
- Bus Error, Address Error, Illegal Instruction, Zero Divide, CHK Instruction,
- TRAPV Instruction, Privilege Violation, Trace, Line 1010 Emulation, Line
- 1111 Emulation, Next (used with [Next]), and, if the trap type is none of
- the above, trap nnnnnnnn, where nnnnnnnn is the number of the trap that
- occurred.
-
- ** TK **
- This field tries to identify what task/process caused the trap. First
- (line 12) are the letters "PROC" or "TASK", stating whether the target is
- a task or a process. In this case, demo was started by a CLI, and so is a
- process.
- To the right of this are up to 19 characters of text. These are the "best"
- name for the target TrapII could find:
- If the target is a task, then this is the name of the task, as pointed to
- by LN_NAME(target task structure).
- If the target is a process, then
- If the target has a CLI, then
- If the CLI has a non null command name (pointed to by cli_CommandName),
- then this is that command name.
- else this is the task name, just as if the target were a task.
- Below (line 13) gives the address of the target's task/process structure.
-
- ** TM **
- This is the system time at which the trap occurred. This is not very exact,
- but it will allow you to look at multiple TrapII windows, and determine
- which is the "freshest." The time is the ONLY numerical value that is not
- in hexadecimal in the TrapII windows.
-
- ** GG **
-
- [Restart] (or the R key)
- This sets the target running where it stopped with the trace bit cleared.
- This only works if a set of conditions are all met:
- [RemTask()] has not been used.
- The trap was due to a TRAP #n instruction or a Trace (or a Next, which is
- really a TRAP #$n).
- The target has some signal bits allocated that are not used by its exception
- code. (as of now, signal bits 0-15 are guarenteed to fall in this category,
- so don't worry about this)
- And the target has entered a wait state. (the target has proceeded out of
- my trap handler, to some shutdown code. Again, this isn't important unless
- some other higher priority task has blocked the target from running)
- This function allows TrapII to be used to halt/look at your program at
- selected places by putting a TRAP instruction where you want to halt and
- look at your program, or restart your program to full speed execution after
- you have stopped it.
- Once the target has been restarted, the gadgets are replaced by the text
- "Target Restarted" until the target enters its exception code again (say,
- from a TRAP #$n which you placed in your code, or [Next]'s ILLEGAL at the
- exit of the subroutine which you [Next]ed into).
-
- [Trace] (or the T key)
- This sets the target running where it stopped with the trace bit set. Same
- conditions as for [Restart] apply.
- It's implementation looks at the next instruction. If it is a TRAP, TRAPV,
- and V is set, or BKPT, then the instruction is just executed, with the
- trace bit off.
- If the instruction is a CHK or a DIV, no tracing is tried, because the
- potential double trap due to CHK being out of bounds or a DIV by 0 and the
- Trace sends the TrapII trap handler into a guru! Therefore a "Next" is always
- used when you try to [Trace] these instructions (this is done automatically
- for you, you just press [Trace])
- Note that this does not handle all cases: especially odd address errors.
- If you trace over an odd address error, you will GURU because TrapII cannot
- handle multiple exceptions at once (it's not TrapII's problem, it's the
- exec.library's)
-
- [Next] (or the N key)
- This only works on a few instructions. It puts a ILLEGAL just beyond the
- next instruction, then sets the target running where it stopped with the
- trace bit cleared. It only works on BCC, BSR, DBCC and JSR instructions,
- and uses the address of the instruction following the BCC, BSR, DBCC or
- JSR, and on the BRA.s, BRA and JMP instruction, where it uses the address
- on the stack (this is an easy speed up when a subroutine ends with the
- calling of another subroutine) (if you try to [Trace] a CHK or DIV, the
- [Next] function is used, but you cannot explicitly [Next] a CHK or DIV).
- The idea of this is to allow subroutines (or system calls) that you know
- work/don't want to trace through to execute a full speed, but still stop
- the target when it returns back to the subroutine level at which you were.
- Once the target stops because of the ILLEGAL, the word I changed in order
- to put a ILLEGAL is restored, and the task is stopped for a Next trap.
- [Next], of course, does not work if you are in ROM, since it must alter the
- next instruction.
- While a [Next] is being happening, the window is not closed, but the
- gadgets are replaced by "-Doing [Next]-" to tell you that the target is
- executing.
- NOTE: If you close the window of a task which is [Nexting] then the code
- is restored; you have essentially done a [Restart].
- You may nest [Next]'s as much as you like. (until you run out of memory,
- actually)
- NOTE: if the subroutines called are such that the target never gets back
- to the instruction following the BCC, BSR, DBCC or JSR, or the address on
- the stack at a BRA or JMP then by doing a [Next] you have essentially done a
- [Restart], since the target will never get back to the ILLEGAL which would
- stop it. You will not confuse TrapII by doing this, but remember that the
- instruction (or first word thereof) which was changed to a ILLEGAL is not
- restored until THAT ILLEGAL is reached.
- NOTE: since [Next] changes your code, if several tasks are running on the
- same code, all of them will react to the change; the target will find a
- Next exception, the others will find an ILLEGAL instruction, and will not
- not be able to restart.
- NOTE: since [Next] reacts differently for a BRA and a BCC, you cannot [Next]
- through a subroutine which you get to by a BCC.
-
- [RemTask()]
- This does a RemTask(target). It is provided in order to unclutter your
- system task list of "old" invocations of your program OR to stop any excep-
- tion code from executing. If the target uses exception code, then you have
- better use this if you don't want your exception code to execute; TrapII
- does nothing to halt exception processing.
- After this function is used, [Restart] and such can no longer be used.
- This function does not close the TrapII window.
- This function does not free any memory used by the target, not even the
- target's TC_MEMENTRY. The TC_MEMENTRY list header is restored after the
- RemTask() for your own post-death enjoyment.
-
- In addition:
-
- The Close Window Gadget
- This closes the TrapII window, and leaves the target as it is. If the
- target is not executing ([Restart], [Trace] or [Next]), and [RemTask()] has
- not been used, then the target is in a wait state, waiting for nothing
- (Wait(0)).
- If, during a [Restart], [Trace] or [Next] you close the window, then if some
- of you code has been changed in order to do a [Next], that code is restored
- in the process of closing the window. This means that if you close the
- window during a [Next] then you could just as well have done a [Restart],
- since the instruction(s) which would have stopped the target at the exit of
- the subroutine(s) is (are) now gone.
-
- The Zoom Gadget
- This shrinks the window to a small bar. To reopen the window, click the
- the zoom gadget again.
-
- Back to the demo:
- Since our trap is a TRAP #0 instruction, we can use [Restart] to continue.
- Press it now. The task "demo" is restarted, executes the next instruction,
- TRAP #$F, enters exception handling code, which culminates in TrapII
- updating its window for the target with this new information.
- This is another TRAP #n instruction trap, so nothing much is new (except
- the PC has incremented by 2).
- Now lets try to trace through the loop. Press [Trace]. The task "demo"
- is restarted, but because the trace bit is set, one instruction executes
- and then the CPU internally generates trace exception, which causes it
- to enter exception handling code, and eventually TrapII undates the
- window to inform you of this. Keep pressing [Trace] and see the PC run
- through the loop, d0 count down and d1 count up.
- When you are tired of this, press [Restart]. Now the task "demo" is
- restarted with the trace bit cleared, so now it runs full speed until it
- finds the TRAP #$1 at the end of the loop. Since the next instruction
- is a BSR.S, we can use [Next] to let the subroutine execute at full speed
- but yet gain control of the target back once the subroutine is finished.
- Press [Next], and the subroutine counts down, returns, and then causes
- a Next trap. [Next] is a way to "trace" through subroutines that you are
- not interrested in actually [Trace]ing through (like system calls or
- subroutines that you know (ha!) have no bugs). And we could have used
- [Next] to trace through our dbf.w loop by pressing [Next] when the PC
- pointed to the dbf.w instruction. That is usefull when there is not
- TRAP instruction following the loop.
- Press [Restart] to send the target going again until it causes an address
- error as it tries to load from the odd address label+1.
- Now the AD field is filled in.
-
- ** AD **
- This shows the information the 680x0 dumps in its stack frame when a bus or
- address error occurs. It should look like:
-
- +
- line 1 FUNC W,I,UsDt|
- 2 33c1 |
- 3 ADDR nnnnnnnn|
- 4 /00000009,00|
- 5 INST 33c0 |
-
- FUNC shows the specific information concerning the memory access that
- caused the bus/address error.
- The first letter gives the direction of the access, W = write, R = read.
- The second letter gives what state the 68000 was in when the error occured
- I = executing an instruction, N = not executing an instruction (responding
- to an interrupt, another trap, etc...)
- The third field represents the function code that was on pins FC0,FC1 and
- FC2 of the 68000. It can be:
- UsDt...user data ; accessing source or destination
- UsPg...user program ; reading an instruction
- SpDt...supervisor data
- SpPg...supervisor program
- IAck...interrupt acknowledge
- ????...something else TrapII doesn't know how to interpret.
- Below (line 2) is the whole hex value of the function code the 68000 dumped
- on the stack. This is only useful if TrapII's interpretation of this value
- is not enough.
-
- ADDR shows the address that caused the bus/address error. It is given
- first as an absolute address (line 3), then as an offset and hunk number
- (line 4), like the PC.
-
- INST shows the hex value of the instruction the 68000 was executing when the
- trap occurred.
-
-
-
- How TrapII works:
- (limited overview, skips many details, but lets you know what happens to
- the target)
-
- TrapII adds to the AddTask() call a bit of code that compares the new
- task's trap code (TC_TRAPCODE) with both the system default (TaskTrapCode*)
- and the TC_TRAPCODE of TrapII itself. This is because TC_TRAPCODE of a
- task started by a CLI or workbench is not the system default (I don't know
- why). If the new task is using either, then TC_TRAPCODE is changed to
- point to TrapII's trap handler.**
-
- Then TrapII waits for a signal from its trap handler.
-
- When a new task causes a trap to occur (and has not installed its own trap
- handler), TrapII's handler is executed.
- The handler dumps the 680x0's registers, the 680x0's stack frame in a
- buffer, signals TrapII, and invents a new stack frame that clears T and S
- bits of the SR, and changes the PC to point to TrapII's target_wait code,
- points the USP to TrapII's ministack, and rte's.
-
- The target now executes the target_wait code, which does a Wait(0).
-
- TrapII is reawakened, opens or redraws a window and all that, and goes back
- to sleep.
-
- When [Restart], [Trace] or [Next] is hit, then the target's wait stack frame
- is altered to point to TrapII's restart_target code, and the target is
- reawakened by changing TC_SIGWAIT to be all possible non-exception causing
- signals, and then Signal()ing the target.
-
- The target now executes the restart_target code, which restores TC_SIGRCEVD,
- the registers to what was displayed in the TrapII window, and control
- proceeds to where the target left off.
-
- [Next] is done by computing the length of the BSR[.S] or JSR, or getting
- the "return address" off the top of the stack, and putting a BKPT #0 at that
- next instruction. Then, whenever that task traps, if it trapped because
- of that BKPT #0, then it is cosidered a Next trap, the word altered to put
- the BKPT #0 is restored.
- You can see this for yourself: [Next] into a loop that contains a TRAP #n.
- Once the target has hit the TRAP #$n, look at the instruction following the
- BSR or JSR you used to enter the subroutine. It will be the BKPT #0 TrapII
- put there. Once you [Restart] the target, and it exits the subroutine,
- TrapII's BKPT #0 is reached, and the code is restored to what is was
- before, which your disassembler will show you if you look at that
- address again.
-
- * TrapII does NOT change TaskTrapCode(execbase), because I do not see any
- advantage in doing this; I found no task that used it.
-
- ** This way, if a task is going to use its own trap handler, either by
- later changing the value TC_TRAPCODE, or by having the task's launcher set
- it, TrapII will not get in the way.
- This also means any task started before TrapII was run will still be using
- the system's trap handler, which is why `run' was required to run the demo.
-
-
-
- Limitations, Problems & Additional Notes:
-
- Because of the way the trap handler and TrapII interact, there is a short
- time period between the time the trap occurred and the window is opened
- during which a second trap, will not be reported by TrapII. However, the
- offending task will be put into a perpetual wait state (Wait(0)).
- This time period lasts from when the trap occurs to a bit before the window
- is opened. This includes two AllocMem() calls.
-
- It is not such a good idea to have TrapII running at a very low priority;
- In order to display its windows, TrapII does have to run. Priority 0 is
- good enough in most cases, but if you have customized the priorities of
- various tasks on your system, then you may need to run TrapII at a different
- priority.
-
- TrapII will only effect tasks started (AddTask()) after it was run.
- This means that if you open a CLI, type "run trapii", then "your program",
- your program will NOT be using TrapII's trap handler, because "your program"
- is running using the CLI's task structure, and that was added to the system
- when the CLI was opened--before TrapII was run. However, if you typed "run
- your program", "your program" would use TrapII's trap handler, because run
- started a new task for "your program", and that task was started after
- TrapII was run.
-
-
-
- Use:
-
- Because targets started different ways seem to have different trap handling
- code, in order to be sure TrapII will work, TrapII must be started in the
- same manner the target will be started. For this reason, TrapII can be
- started from both a CLI or Workbench. It is true that sometimes, on some
- setups, with some programs running or not running, that a TrapII started
- one way can trap programs started another. However this behavior cannot be
- guaranteed; if it works on your system, use it if you like, but remember
- if, all of a sudden, TrapII isn't intercepting your program's errors any
- more, you will have to start TrapII the way I recommend.
-
- NOTE: the author has used this program to debug AmigaDOS device handlers
- under 1.3 and 2.04/2.1 by starting TrapII running with
- run TrapII
- from a CLI. I guess the DOS's startup-a-handler routine uses the same trap
- handler as run. However C= makes no promises that this will work forever.
-
- WB:
- just double-click on icon
-
- CLI:
- Here it seems that whether a task is started by:
- target_name
- or with a run, it doesn't change the trap handler so you can start TrapII
- with:
- run TrapII
- or, better, with:
- run <nil: >nil: TrapII
-
- If TrapII must be started at a non zero priority (let's use 3), then you
- can use either:
- ChangeTaskPri 1
- Run TrapII
- or better,
- run <nil: >nil: ChangeTaskPri 1 +
- TrapII
-
- Now clever users may well be thinking of putting these last two
- lines in their startup-sequence, and that works for the author under
- 2.x.
-
-
-
- I can be reached through:
-
- Nicolas Dade
- 405 W Delaware
- Urbana, IL, 61801 (USA)
-
- or nicolas-dade@uiuc.edu
-
-
-
-